/**
 * @file drm_device.h
 * @brief DRM display handling header.
 *
 * Defines the context, buffer structures, and function prototypes for
 * managing a DRM display device. This version has been upgraded to use the
 * modern DRM Atomic KMS API for non-blocking page flips with proper scaling.
 */

#ifndef DRM_DISPLAY_H
#define DRM_DISPLAY_H

#include <xf86drm.h>
#include <xf86drmMode.h>
#include <drm_fourcc.h>
#include <stdbool.h>
#include "util.h"

// Stores information for a single DRM buffer (backed by DMABUF)
struct drm_buffer
{
    unsigned int bo_handle; // Buffer Object handle
    unsigned int fb_handle; // Framebuffer handle
    int dma_fd;             // Exported DMABUF file descriptor
};

// Context structure holding all DRM-related information
typedef struct drm_device
{
    int fd;
    char *module;

    // Display properties
    int width;              // Desired display width (for mode matching)
    int height;             // Desired display height (for mode matching)
    unsigned int out_fourcc;
    drmModeModeInfo mode;   // The actual selected display mode

    // DRM object IDs (found automatically)
    uint32_t crtc_id;
    uint32_t plane_id;
    uint32_t connector_id; // Added for atomic modesetting

    // DRM property IDs (for atomic commits)
    uint32_t prop_crtc_id;
    uint32_t prop_fb_id;
    uint32_t prop_src_x, prop_src_y, prop_src_w, prop_src_h;
    uint32_t prop_crtc_x, prop_crtc_y, prop_crtc_w, prop_crtc_h;

    int crtc_idx;

    // Buffer management
    unsigned int buffer_count;
    struct drm_buffer *buffers;
    int buffer_width;       // Actual width of the created buffers
    int buffer_height;      // Actual height of the created buffers

    // Page flip handling
    drmEventContext ev_ctx;
    volatile bool page_flip_pending;

} drm_device_t;

// --- Public API Functions ---

// Initialization and Cleanup
int drm_init(drm_device_t *ctx);
void drm_cleanup(drm_device_t *ctx);

// Buffer Management
int drm_create_buffers(drm_device_t *ctx, int width, int height);

/**
 * @brief Sets the display plane to an initial buffer using a blocking atomic commit.
 *
 * This synchronous call is used only once to set up the display pipeline
 * before the main rendering loop begins, ensuring proper scaling from the start.
 *
 * @param ctx Pointer to the DRM context.
 * @param buffer_index The index of the buffer to display.
 * @return 0 on success, -1 on failure.
 */
int drm_set_plane(drm_device_t *ctx, int buffer_index);


/**
 * @brief Requests a page flip using a non-blocking atomic commit.
 *
 * This asynchronous function queues a request to update the plane's framebuffer
 * property. The change will take effect at the next vertical blanking interval,
 * preventing tearing and ensuring the image is correctly scaled every frame.
 *
 * @param ctx Pointer to the DRM context.
 * @param buffer_index The index of the buffer to display.
 * @return 0 on success, -1 on failure.
 */
int drm_page_flip(drm_device_t *ctx, int buffer_index);


/**
 * @brief Waits for a previously queued page flip to complete.
 *
 * This function blocks until the display controller signals that the
 * flip has occurred via a DRM event.
 *
 * @param ctx Pointer to the DRM context.
 * @return 0 on success, -1 on failure.
 */
int drm_wait_for_flip(drm_device_t *ctx);

#endif // DRM_DISPLAY_H
